package com.ljdemo.lrecorder.activity

import android.Manifest
import android.content.Context
import android.content.DialogInterface
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.ImageFormat
import android.graphics.SurfaceTexture
import android.hardware.camera2.CameraAccessException
import android.hardware.camera2.CameraCaptureSession
import android.hardware.camera2.CameraCharacteristics
import android.hardware.camera2.CameraDevice
import android.hardware.camera2.CameraManager
import android.hardware.camera2.CaptureFailure
import android.hardware.camera2.CaptureRequest
import android.hardware.camera2.CaptureResult
import android.hardware.camera2.TotalCaptureResult
import android.media.MediaRecorder
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Environment
import android.os.Handler
import android.os.HandlerThread
import android.provider.Settings
import android.util.Log
import android.util.Size
import android.view.Surface
import android.view.TextureView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import com.ljdemo.lrecorder.databinding.ActivityPictureRecordBinding
import com.ljdemo.lrecorder.utils.AlertUtil
import com.ljdemo.lrecorder.utils.FileUtil
import java.io.File

class PictureRecordActivity : AppCompatActivity() {

    companion object{
        private const val permission_request_code=1002
        private val TAG=PictureRecordActivity::class.java.simpleName
    }

    private lateinit var cameraManager:CameraManager
    private var cameraDevice: CameraDevice? = null
    private lateinit var previewCaptureRequest: CaptureRequest.Builder
    private lateinit var sessionStateCallback: CameraCaptureSession.StateCallback
    private var cameraFlag=0 //摄像头标志，0为前置，1为后置，2为外置
    private lateinit var currentSelectCamera:String // 当前选择的相机
    private lateinit var childHandler:Handler
    private var isRecord = false
    private lateinit var mediaRecorder : MediaRecorder
    private var cameraCaptureSession: CameraCaptureSession? = null
    private lateinit var sessionCaptureCallback:CameraCaptureSession.CaptureCallback

    private val videoSaveDir : String by lazy {
        getExternalFilesDir(Environment.DIRECTORY_MOVIES).toString() + File.separator
    }

    private lateinit var binding:ActivityPictureRecordBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding=ActivityPictureRecordBinding.inflate(layoutInflater)
        setContentView(binding.root)

        checkPermission()
        initView()
        initChildHandler()
        initTextureViewStateListener()
        initMediaRecorder()
        initSessionStateCallback()
        initSessionCaptureCallback()
    }

    private fun initSessionCaptureCallback() {
        sessionCaptureCallback=object : CameraCaptureSession.CaptureCallback(){
            override fun onCaptureStarted(
                session: CameraCaptureSession,
                request: CaptureRequest,
                timestamp: Long,
                frameNumber: Long
            ) {
                super.onCaptureStarted(session, request, timestamp, frameNumber)
            }

            override fun onCaptureProgressed(
                session: CameraCaptureSession,
                request: CaptureRequest,
                partialResult: CaptureResult
            ) {
                super.onCaptureProgressed(session, request, partialResult)
            }

            override fun onCaptureCompleted(
                session: CameraCaptureSession,
                request: CaptureRequest,
                result: TotalCaptureResult
            ) {
                super.onCaptureCompleted(session, request, result)
            }

            override fun onCaptureFailed(
                session: CameraCaptureSession,
                request: CaptureRequest,
                failure: CaptureFailure
            ) {
                super.onCaptureFailed(session, request, failure)
            }
        }
    }

    private fun initSessionStateCallback() {
        sessionStateCallback=object : CameraCaptureSession.StateCallback() {
            override fun onConfigured(session: CameraCaptureSession) {
                //执行重复获取数据请求，等于一直获取数据呈现预览画面，sessionCaptureCallback会返回此次操作的信息回调
                cameraCaptureSession = session
                cameraCaptureSession!!.setRepeatingRequest(previewCaptureRequest.build(),
                    sessionCaptureCallback,
                    childHandler)
            }

            override fun onConfigureFailed(session: CameraCaptureSession) {
                Toast.makeText(this@PictureRecordActivity,"配置失败",Toast.LENGTH_LONG).show()
            }

        }
    }

    private fun initMediaRecorder() {
        mediaRecorder = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            MediaRecorder(this)
        }else{
            MediaRecorder()
        }
    }

    private fun initView(){
        // 设置TextureView的纹理生成监听
        binding.prTv.surfaceTextureListener = object : TextureView.SurfaceTextureListener{
            override fun onSurfaceTextureAvailable(p0: SurfaceTexture, p1: Int, p2: Int) {
                // 纹理可用

                initCamera()
            }

            override fun onSurfaceTextureSizeChanged(p0: SurfaceTexture, p1: Int, p2: Int) {
                //纹理尺寸变化
            }

            override fun onSurfaceTextureDestroyed(p0: SurfaceTexture): Boolean {
                //纹理被销毁
                return false
            }

            override fun onSurfaceTextureUpdated(p0: SurfaceTexture) {
                //纹理更新
            }

        }
    }


    // 检查权限
    private fun checkPermission():Boolean{
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
            // 需要申请的权限数组
            val permissions:Array<String> = arrayOf(
                Manifest.permission.RECORD_AUDIO,// 录音权限
                Manifest.permission.WRITE_EXTERNAL_STORAGE,// 写文件权限
                Manifest.permission.READ_EXTERNAL_STORAGE,// 读文件权限
                Manifest.permission.CAMERA// 相机
            )
            for (permission:String in permissions){
                if (ContextCompat.checkSelfPermission(this,permission) != PackageManager.PERMISSION_GRANTED){
                    // 发现没有权限
                    // 自动申请
                    ActivityCompat.requestPermissions(this,permissions,
                        permission_request_code
                    )
                    return false
                }
            }
        }
        return true
    }

    // 初始化相机管理
    private fun initCamera(){
        cameraManager=getSystemService(Context.CAMERA_SERVICE) as CameraManager
        selectCamera(cameraFlag)
        openCamera()
    }

    private fun initTextureViewStateListener(){
        binding.prTv.surfaceTextureListener = object : TextureView.SurfaceTextureListener{
            override fun onSurfaceTextureAvailable(
                surface: SurfaceTexture,
                width: Int,
                height: Int
            ) {
                //可以使用纹理

                initCameraManager()
            }

            override fun onSurfaceTextureSizeChanged(
                surface: SurfaceTexture,
                width: Int,
                height: Int
            ) {
                //纹理尺寸变化
            }

            override fun onSurfaceTextureDestroyed(surface: SurfaceTexture): Boolean {
                //纹理被销毁
                return false
            }

            override fun onSurfaceTextureUpdated(surface: SurfaceTexture) {
                //纹理更新
            }

        }
    }

    private fun initCameraManager(){
        // 初始化Camera2的相机管理，CameraManager用于获取摄像头分辨率，摄像头方向，摄像头id与打开摄像头的工作
        cameraManager = getSystemService(CAMERA_SERVICE) as CameraManager
        selectCamera(cameraFlag)
        openCamera()
    }

    /**
     * 选择一颗我们需要使用的摄像头，主要是选择使用前摄还是后摄或者是外接摄像头
     * CameraCharacteristics.LENS_FACING_FRONT = 0
     * CameraCharacteristics.LENS_FACING_BACK = 1
     * CameraCharacteristics.LENS_FACING_EXTERNAL = 2
     * @param cameraFlag 0 为前置摄像头，1 为后置，2 为外部摄像头
     */
    private fun selectCamera(cameraFlag:Int){
        // 获取当前设备的全部摄像头id集合
        var cameraIdList = cameraManager.cameraIdList
        if (cameraIdList.isEmpty()){
            Log.e(TAG,"获取相机id列表为空")
        }
        for (cameraId in cameraIdList){
            //得到当前id的摄像头描述特征
            val cameraCharacteristics = cameraManager.getCameraCharacteristics(cameraId)
            //获取摄像头的方向特征信息
            val facing = cameraCharacteristics.get(CameraCharacteristics.LENS_FACING)
            if (facing==cameraFlag){
                currentSelectCamera=cameraId
            }
        }
    }

    private fun openCamera(){
        // 检查权限
        if (ActivityCompat.checkSelfPermission(
                this,
                Manifest.permission.CAMERA
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            // 弹窗提示没有权限
            AlertUtil.alert(this,"没有权限","没有相机的权限录像功能将无法使用","去开启权限","取消",
                object : DialogInterface.OnClickListener{
                    override fun onClick(p0: DialogInterface?, p1: Int) {
                        // 跳转到系统设置该应用的信息页去开启权限
                        val intent = Intent()
                        intent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
                        val uri = Uri.fromParts("package", packageName, null)
                        intent.data = uri
                        startActivityForResult(intent, 200)// 已弃用

                        p0?.dismiss()
                    }

                },object : DialogInterface.OnClickListener{
                    override fun onClick(p0: DialogInterface?, p1: Int) {
                        p0?.dismiss()
                    }

                })
            return
        }

        // 打开摄像头
        cameraManager.openCamera(currentSelectCamera,object : CameraDevice.StateCallback(){
            override fun onOpened(p0: CameraDevice) {
                // 摄像头被打开
                cameraDevice=p0
                //计算获取需要的摄像头分辨率
                val cameraSize = getMatchingSize()
                //得到纹理
                //val surfaceTexture = textureView.surfaceTexture
                val surfaceTexture = binding.prTv.surfaceTexture
                surfaceTexture!!.setDefaultBufferSize(cameraSize!!.width,cameraSize!!.height)
                val previewSurface = Surface(surfaceTexture)
                previewCaptureRequest = cameraDevice!!.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)
                previewCaptureRequest.set(CaptureRequest.CONTROL_AF_MODE,CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE)
                previewCaptureRequest.addTarget(previewSurface)
                //创建数据捕获会话，用于摄像头画面预览，这里需要等待mSessionStateCallback回调
                cameraDevice!!.createCaptureSession(listOf(previewSurface),sessionStateCallback,childHandler)

            }

            override fun onDisconnected(p0: CameraDevice) {
                AlertUtil.showCenterToast(this@PictureRecordActivity,"摄像头断开")
            }

            override fun onError(p0: CameraDevice, p1: Int) {
                AlertUtil.showCenterToast(this@PictureRecordActivity,"出现错误")
            }

        },childHandler)
    }

    private fun closeCamera(){
        cameraCaptureSession?.close()
        cameraCaptureSession=null
        cameraDevice?.close()
        cameraDevice=null

    }

    private fun initChildHandler(){
        val handlerThread=HandlerThread("PictureRecord")
        handlerThread.start()
        childHandler= Handler(handlerThread.looper)
    }

    /**
     * 重新配置录制视频时的CameraCaptureSession
     * */
    private fun reconfigure(){
        //停止预览，准备切换到录制视频
        cameraCaptureSession?.stopRepeating()
        //关闭预览的会话，需要重新创建录制视频的会话
        cameraCaptureSession?.close()
        cameraCaptureSession=null
        configMediaRecorder()
        val cameraSize = getMatchingSize()
        val surfaceTexture = binding.prTv.surfaceTexture
        surfaceTexture?.setDefaultBufferSize(cameraSize!!.width,cameraSize!!.height)
        val previewSurface = Surface(surfaceTexture)
        val recorderSurface = mediaRecorder.surface

        previewCaptureRequest= cameraDevice!!.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)
        previewCaptureRequest.set(CaptureRequest.CONTROL_AF_MODE,CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE)
        previewCaptureRequest.addTarget(previewSurface)
        previewCaptureRequest.addTarget(recorderSurface)
        cameraDevice!!.createCaptureSession(listOf(previewSurface,recorderSurface),sessionStateCallback,childHandler)

    }

    /**
     * 配置录制视频相关数据
     * */
    private fun configMediaRecorder(){
        val filename = FileUtil.getFlagName() + ".mp4"
        val file = File(videoSaveDir, filename)
        mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC)
        mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE)
        mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
        mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC)
        mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264)
        val size = getMatchingSize()
        mediaRecorder.setVideoEncodingBitRate(8* size!!.width*size!!.height)
        mediaRecorder.setVideoFrameRate(30)
        mediaRecorder.setVideoSize(size.width,size.height)
        val surface = Surface(binding.prTv.surfaceTexture)
        mediaRecorder.setPreviewDisplay(surface)
        mediaRecorder.setOutputFile(file.absolutePath)

        if (cameraFlag == 0){
            //如果是前置摄像头，旋转录制画面270
            mediaRecorder.setOrientationHint(270)
        }else if (cameraFlag == 1){
            //如果是后置摄像头，旋转录制画面90
            mediaRecorder.setOrientationHint(90)
        }

        mediaRecorder.prepare()

    }

    /**
     * 开始录制视频
     */
    private fun startRecorder() {
        mediaRecorder.start()
    }

    /**
     * 暂停录制视频（暂停后视频文件会自动保存）
     */
    private fun stopRecorder() {
        mediaRecorder.stop()
        mediaRecorder.reset()
    }

//    private fun getMatchingSize(): Size? {
//        val width = binding.prTv.width
//        val height = binding.prTv.height
//        return Size(width,height)
//    }

    /**
     * 计算需要的使用的摄像头分辨率
     */
    private fun getMatchingSize(): Size? {
        var selectSize: Size? = null
        try {
            val cameraCharacteristics = cameraManager.getCameraCharacteristics(
                currentSelectCamera
            )
            val streamConfigurationMap = cameraCharacteristics.get(
                CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP
            )
            val sizes = streamConfigurationMap!!.getOutputSizes(ImageFormat.JPEG)
            //因为我这里是将预览铺满屏幕,所以直接获取屏幕分辨率
            val displayMetrics = resources.displayMetrics
            //屏幕分辨率宽
            val deviceWidth = displayMetrics.widthPixels
            //屏幕分辨率高
            val deviceHeight = displayMetrics.heightPixels

            Log.i(
                TAG,
                "getMatchingSize2: 屏幕密度宽度=$deviceWidth"
            )
            Log.i(
                TAG,
                "getMatchingSize2: 屏幕密度高度=$deviceHeight"
            )

            // 获取组件分辨率
            //val deviceWidth = binding.prTv.width
            //val deviceHeight = binding.prTv.height

            /**
             * 循环40次,让宽度范围从最小逐步增加,找到最符合屏幕宽度的分辨率,
             * 你要是不放心那就增加循环,肯定会找到一个分辨率,不会出现此方法返回一个null的Size的情况
             * ,但是循环越大后获取的分辨率就越不匹配
             */
            for (j in 1..40) {
                for (i in sizes.indices) { //遍历所有Size
                    val itemSize = sizes[i]
                    Log.i(
                        TAG,
                        "当前itemSize 宽=" + itemSize.width + "高=" + itemSize.height
                    )
                    //判断当前Size高度小于屏幕宽度+j*5  &&  判断当前Size高度大于屏幕宽度-j*5  &&  判断当前Size宽度小于当前屏幕高度
                    if (itemSize.height < deviceWidth + j * 5 && itemSize.height > deviceWidth - j * 5) {
                        if (selectSize != null) { //如果之前已经找到一个匹配的宽度
                            if (Math.abs(deviceHeight - itemSize.width) < Math.abs(deviceHeight - selectSize.width)) { //求绝对值算出最接近设备高度的尺寸
                                selectSize = itemSize
                                continue
                            }
                        } else {
                            selectSize = itemSize
                        }
                    }
                }
                if (selectSize != null) { //如果不等于null 说明已经找到了 跳出循环
                    break
                }
            }
        } catch (e: CameraAccessException) {
            Log.e(
                TAG,
                e.message!!
            )
            e.printStackTrace()
        }
        Log.i(
            TAG,
            "getMatchingSize2: 选择的分辨率宽度=" + selectSize!!.width
        )
        Log.i(
            TAG,
            "getMatchingSize2: 选择的分辨率高度=" + selectSize.height
        )
        return selectSize
    }
}